﻿using DotNetty.Common.Utilities;
using DotNetty.Transport.Channels;
using Microsoft.Extensions.Configuration;
using PSAMMatrixCloud.Common;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Net;
using PSAMMatrixCloud.Model;

namespace PSAMMatrixCloud.TransferSecret.LaneMutual
{
    /// <summary>
    /// Channel Manager
    /// </summary>
    public static class LaneChannelManager
    {
        public static readonly AttributeKey<SessionInfo> SESSION_KEY = AttributeKey<SessionInfo>.ValueOf("lanesession.key");

        private static readonly ConcurrentDictionary<string, IChannel> dicChannel = new ConcurrentDictionary<string, IChannel>();
        private static readonly ConcurrentDictionary<EndPoint, ChannelSession> connChannels = new ConcurrentDictionary<EndPoint, ChannelSession>();

        public static void Add(string deviceID, IChannel channel)
        {
            if (dicChannel.TryGetValue(deviceID, out IChannel oldChannel))
            {
                if (oldChannel.Equals(channel))
                {
                    return;
                }
                LogHelper.Error($"设备:{deviceID} 连接已经存在，关闭旧连接");
                if (oldChannel.Active)
                {
                    oldChannel.CloseAsync();
                }
            }

            dicChannel[deviceID] = channel;
            ChannelRemove(channel);
            LogHelper.Info($"建立{deviceID} 会话");
        }

        public static IChannel GetChannel(string deviceID)
        {
            if (dicChannel.TryGetValue(deviceID, out IChannel value))
            {
                return value;
            }

            return null;
        }

        public static string GetDeviceID(IChannel channel)
        {
            IAttribute<SessionInfo> attribute = channel.GetAttribute<SessionInfo>(LaneChannelManager.SESSION_KEY);
            return attribute.Get()?.DeviceID;
        }

        public static SessionInfo GetSessionInfo(IChannel channel)
        {
            IAttribute<SessionInfo> attribute = channel.GetAttribute<SessionInfo>(LaneChannelManager.SESSION_KEY);
            return attribute.Get();
        }

        public static void Remove(IChannel channel)
        {
            string deviceID = dicChannel.FirstOrDefault(item => item.Value == channel).Key;
            if (!string.IsNullOrWhiteSpace(deviceID))
            {
                dicChannel.TryRemove(deviceID, out IChannel value);
            }
        }

        public static IChannel GetChannel(string PSAMMatrixNo, string PSAMNo, string TerminalNo)
        {
            try
            {
                IAttribute<SessionInfo> attribute = null;
                foreach (var ChannelSession in dicChannel)
                {
                    attribute = ChannelSession.Value.GetAttribute<SessionInfo>(LaneChannelManager.SESSION_KEY);
                    if (attribute != null)
                    {
                        var LaneSession = attribute.Get();
                        if (LaneSession != null)
                        {
                            if (LaneSession.PSAMNo == PSAMNo && LaneSession.PSAMMatrixNo == PSAMMatrixNo && LaneSession.TerminalNo == TerminalNo)
                            {
                                return ChannelSession.Value;
                            }
                        }
                    }

                }
            }
            catch (Exception ex)
            {
                Common.LogHelper.Error("车道回话异常", ex);
            }
            return null;
        }

        /// <summary>
        /// 连接会话
        /// </summary>
        /// <param name="context"></param>
        public static void ChannelActive(IChannelHandlerContext context)
        {
            Common.LogHelper.Info("建立会话id：" + context.Channel.RemoteAddress);
            connChannels.GetOrAdd(context.Channel.RemoteAddress, new ChannelSession() { channel = context.Channel, CreateTime = DateTime.Now });
        }

        /// <summary>
        /// 移除会话
        /// </summary>
        /// <param name="context"></param>
        public static void ChannelRemove(IChannel channel)
        {
            try
            {
                Common.LogHelper.Info("移除会话id：" + channel.RemoteAddress);
                ChannelSession value = null;
                connChannels.Remove(channel.RemoteAddress, out value);
            }
            catch (Exception ex)
            {
                LogHelper.Error("移除会话异常", ex);
            }
        }

        /// <summary>
        /// 检测会话生命周期（2分钟内）
        /// </summary>
        /// <param name="obj"></param>
        public static void KeepAliveAsync()
        {
            int AlivePeriod = 120;

            try
            {

                if (!string.IsNullOrWhiteSpace(PSAMSeetings.AlivePeriod))
                {
                    AlivePeriod = Math.Abs(int.Parse(PSAMSeetings.AlivePeriod));
                }
                LogHelper.Info($"车道会话生命周期检测,【连接空闲会话数：{connChannels.Count}  信任通道数：{dicChannel.Count } 】  会话生命周期:{AlivePeriod}秒");
                foreach (var TempChannel in connChannels)
                {
                    try
                    {
                        if (TempChannel.Value.CreateTime.AddSeconds(AlivePeriod) < DateTime.Now)
                        {

                            TempChannel.Value.channel.CloseAsync();
                            ChannelSession channelSession = null;
                            connChannels.Remove(TempChannel.Key, out channelSession);
                        }
                    }
                    catch (Exception ex)
                    {
                        LogHelper.Error("断开空闲连接异常", ex);
                    }
                }

                foreach (var AliveChannel in dicChannel)
                {
                    try
                    {
                        var AliveChannelSession = AliveChannel.Value.GetAttribute<SessionInfo>(LaneChannelManager.SESSION_KEY).Get();
                        if (AliveChannelSession.LastAccessTime.AddSeconds(AlivePeriod) < DateTime.Now)
                        {
                            AliveChannel.Value.CloseAsync();
                            IChannel channel = null;

                            dicChannel.Remove(AliveChannel.Key, out channel);
                        }
                    }
                    catch (Exception ex)
                    {
                        LogHelper.Error("断开车道会话异常", ex);
                    }

                }
            }
            catch (Exception ex)
            {
                LogHelper.Error($"云端秘钥接入服务,检测会话生命周期异常", ex);
            }
        }
    }
}